package com.jsptpd.smartauth.common.config.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jsptpd.smartauth.common.exception.BusinessException;
import com.jsptpd.smartauth.modules.business.model.Error;
import com.jsptpd.smartauth.modules.business.model.RespObj;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by LOG on 2017/11/22.
 * 建议的日志拦截， 解放controller层的日志工作， 按照个人理解来说， 即使整个应用框架
 * 进行了多层分解， 那么理论上来说所有异常需要从下层往上层抛出。  这样配置文件足以应对日志打印的需求
 * 但是对于外部接口的报文日志， 由于要区分职责， 所以需要将所有的报文打印出来，
 * 这里还没有在此日志配置文件有所体现， 后续在详细完善此方面的全局日志打印
 * <p>
 */
@Aspect
@Configuration
public class LogConfig {

    private static final Logger logger = LoggerFactory.getLogger(LogConfig.class);


    /**
     * 定义拦截规则：拦截com.xjj.web.controller包下面的所有类中，有@RequestMapping注解的方法。
     *
     * @param joinPoint
     * @return
     */
    @Around("execution(public * com.jsptpd.smartauth..*.*(..)) && " +
            "@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object print(ProceedingJoinPoint joinPoint) throws IllegalAccessException, InstantiationException {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        StringBuilder sb = new StringBuilder();

        //日志记录存储到数据库
        String url = request.getRequestURL().toString();



        sb.append(" URL:{ " + request.getRequestURL().toString());
        sb.append(" } HTTP_METHOD:{ " + request.getMethod());
        sb.append(" } IP:{ " + request.getRemoteAddr());

//        if (request.getSession() != null && SecurityContextHolder.getContext().getAuthentication() != null) {
//            Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//            if (principal instanceof AbstractUser) {
//                AbstractUser user = (AbstractUser) principal;
//                if (principal != null && user.getUsername() != null) {
//                    sb.append(" } USER:{ " + user.getUsername());
//                }
//            }
//        }


        sb.append(" } CLASS_METHOD:{ " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint
                .getSignature().getName());
        sb.append("\n");
        sb.append(" } PARAM:{ ");

        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (Object param : joinPoint.getArgs()) {
                //如果参数的类型是在命名空间内， 才进行json序列化
                if (param != null) {
                    if (param.getClass().getName().contains("com.jsptpd.smartauth")) {
                        String json = "";
                        try {
                            ObjectMapper mapper = new ObjectMapper();
                            json = mapper.writeValueAsString(param);
                        } catch (Exception ex) {
                        }
                        sb.append(json);

                        // TODO: 2018/3/8 对象转成json，有数据


                    } else { //否则就自求多福的序列化
                        sb.append(String.valueOf(param));

                    }
                }
                sb.append(" ||| ");
            }
        }
        sb.append("}\n");


        try {
            Object result = joinPoint.proceed();
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(result);
            sb.append("RESULT: " + json);
            sb.append("\n");
            logger.info(sb.toString());
            return result;


        } catch (BusinessException throwable) {  //如果是业务异常，则不打印堆栈信息
            logger.info(sb.toString());
            String currentTag = "B" + new Date().getTime();
            logger.info("EXCEPTION{" + currentTag + "}:" + throwable.getMessage());
            if (throwable.getMessage() != null && !"".equals(throwable.getMessage())) {
                //return new ResponseObj<Object>(null, new RetCode("9999", throwable.getMessage(), currentTag));
                return new RespObj<Object>(new Error(9999,throwable.getMessage()),currentTag);
            } else {
                //return new ResponseObj<Object>(null, new RetCode("9999", "请求失败", currentTag));
                return new RespObj<Object>(new Error(9999,"请求失败"),currentTag);
            }

        } catch (Throwable throwable) {
            logger.info(sb.toString());
            String currentTag = "E" + new Date().getTime();
            logger.info("EXCEPTION{" + currentTag + "}:" + throwable.getMessage(), throwable);
            if (throwable.getMessage() != null && !"".equals(throwable.getMessage())) {
//                return new ResponseObj<Object>(null, new RetCode("9999", throwable.getMessage(), currentTag));
                return new RespObj<Object>(new Error(9999,throwable.getMessage()),currentTag);
            } else {
//                return new ResponseObj<Object>(null, new RetCode("9999", "请求失败", currentTag));
                return new RespObj<Object>(new Error(9999,"请求失败"),currentTag);
            }


        }
    }


}
